home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / GNUPLOTsrc.lha / misc.c < prev    next >
C/C++ Source or Header  |  1996-01-26  |  34KB  |  1,249 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: misc.c,v 1.51 1995/12/18 22:41:09 drd Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - misc.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software is provided "as is" without express or implied warranty.
  21.  * 
  22.  *
  23.  * AUTHORS
  24.  *
  25.  *   Original Software:
  26.  *     Thomas Williams,  Colin Kelley.
  27.  * 
  28.  *   Gnuplot 2.0 additions:
  29.  *       Russell Lang, Dave Kotz, John Campbell.
  30.  *
  31.  *   Gnuplot 3.0 additions:
  32.  *       Gershon Elber and many others.
  33.  *
  34.  */
  35.  
  36. #include <math.h>
  37.  
  38. #ifdef AMIGA_AC_5
  39. #include <exec/types.h>
  40. #endif /* AMIGA_AC_5 */
  41.  
  42. #include "plot.h"
  43. #include "setshow.h"
  44.  
  45. extern int key_vpos, key_hpos, key_just;
  46. extern int datatype[];
  47. extern char timefmt[];
  48.  
  49. static void save_range __P((FILE *fp, int axis, double min, double max, int autosc, char *text));
  50. static void save_tics __P((FILE *fp, int where, int axis, struct ticdef *tdef, char *text));
  51. static void save_position __P((FILE *fp, struct position *pos));
  52. static int lf_pop __P((void));
  53. static void lf_push __P((FILE *fp));
  54. static int find_maxl_cntr __P((struct gnuplot_contours *contours, int *count));
  55.  
  56. /* State information for load_file(), to recover from errors
  57.  * and properly handle recursive load_file calls
  58.  */
  59. typedef struct lf_state_struct LFS;
  60. struct lf_state_struct {
  61.     FILE *fp;                /* file pointer for load file */
  62.     char *name;            /* name of file */
  63.     TBOOLEAN interactive;        /* value of interactive flag on entry */
  64.     TBOOLEAN do_load_arg_substitution;  /* likewise ... */
  65.     int inline_num;            /* inline_num on entry */
  66.     LFS *prev;                /* defines a stack */
  67.     char *call_args[10];        /* args when file is 'call'ed instead of 'load'ed */
  68. } *lf_head = NULL;            /* NULL if not in load_file */
  69.  
  70. /* these two could be in load_file, except for error recovery */
  71. extern TBOOLEAN do_load_arg_substitution;
  72. extern char *call_args[10];
  73.  
  74. /*
  75.  * cp_alloc() allocates a curve_points structure that can hold 'num'
  76.  * points.
  77.  */
  78. struct curve_points *
  79. cp_alloc(num)
  80.     int num;
  81. {
  82.     struct curve_points *cp;
  83.     cp = (struct curve_points *) alloc((unsigned long)sizeof(struct curve_points), "curve");
  84.     cp->p_max = (num >= 0 ? num : 0);
  85.     if (num > 0) {
  86.        cp->points = (struct coordinate GPHUGE *)
  87.         alloc((unsigned long)num * sizeof(struct coordinate), "curve points");
  88.     } else
  89.        cp->points = (struct coordinate GPHUGE *) NULL;
  90.     cp->next_cp = NULL;
  91.     cp->title = NULL;
  92.     return(cp);
  93. }
  94.  
  95.  
  96. /*
  97.  * cp_extend() reallocates a curve_points structure to hold "num"
  98.  * points. This will either expand or shrink the storage.
  99.  */
  100. void cp_extend(cp, num)
  101.     struct curve_points *cp;
  102.     int num;
  103. {
  104.  
  105. #if (defined(MSDOS) || defined(_Windows))  &&  !defined(WIN32)
  106.     /* Make sure we do not allocate more than 64k points in msdos since 
  107.      * indexing is done with 16-bit int
  108.      * Leave some bytes for malloc maintainance.
  109.      */
  110.     if (num > 32700)
  111.         int_error("Array index must be less than 32k in msdos", NO_CARET);
  112. #endif /* MSDOS */
  113.  
  114.     if (num == cp->p_max) return;
  115.  
  116.     if (num > 0) {
  117.        if (cp->points == NULL) {
  118.           cp->points = (struct coordinate GPHUGE *)
  119.             alloc((unsigned long)num * sizeof(struct coordinate), "curve points");
  120.        } else {
  121.           cp->points = (struct coordinate GPHUGE *)
  122.             ralloc(cp->points, (unsigned long)num * sizeof(struct coordinate), "expanding curve points");
  123.        }
  124.        cp->p_max = num;
  125.     } else {
  126.        if (cp->points != (struct coordinate GPHUGE *) NULL)
  127.         free(cp->points);
  128.        cp->points = (struct coordinate GPHUGE *) NULL;
  129.        cp->p_max = 0;
  130.     }
  131. }
  132.  
  133. /*
  134.  * cp_free() releases any memory which was previously malloc()'d to hold
  135.  *   curve points (and recursively down the linked list).
  136.  */
  137. void cp_free(cp)
  138. struct curve_points *cp;
  139. {
  140.     if (cp) {
  141.         cp_free(cp->next_cp);
  142.         if (cp->title)
  143.             free((char *)cp->title);
  144.         if (cp->points)
  145.             free((char *)cp->points);
  146.         free((char *)cp);
  147.     }
  148. }
  149.  
  150. /*
  151.  * iso_alloc() allocates a iso_curve structure that can hold 'num'
  152.  * points.
  153.  */
  154. struct iso_curve *
  155. iso_alloc(num)
  156.     int num;
  157. {
  158.     struct iso_curve *ip;
  159.     ip = (struct iso_curve *) alloc((unsigned long)sizeof(struct iso_curve), "iso curve");
  160.     ip->p_max = (num >= 0 ? num : 0);
  161.     if (num > 0) {
  162.        ip->points = (struct coordinate GPHUGE *)
  163.         alloc((unsigned long)num * sizeof(struct coordinate), "iso curve points");
  164.     } else
  165.        ip->points = (struct coordinate GPHUGE *) NULL;
  166.     ip->next = NULL;
  167.     return(ip);
  168. }
  169.  
  170. /*
  171.  * iso_extend() reallocates a iso_curve structure to hold "num"
  172.  * points. This will either expand or shrink the storage.
  173.  */
  174. void iso_extend(ip, num)
  175.     struct iso_curve *ip;
  176.     int num;
  177. {
  178.     if (num == ip->p_max) return;
  179.  
  180. #if (defined(MSDOS) || defined(_Windows))  &&  !defined(WIN32)
  181.     /* Make sure we do not allocate more than 64k points in msdos since 
  182.      * indexing is done with 16-bit int
  183.      * Leave some bytes for malloc maintainance.
  184.      */
  185.     if (num > 32700)
  186.         int_error("Array index must be less than 32k in msdos", NO_CARET);
  187. #endif /* MSDOS */
  188.  
  189.     if (num > 0) {
  190.        if (ip->points == NULL) {
  191.           ip->points = (struct coordinate GPHUGE *)
  192.             alloc((unsigned long)num * sizeof(struct coordinate), "iso curve points");
  193.        } else {
  194.           ip->points = (struct coordinate GPHUGE *)
  195.            ralloc(ip->points, (unsigned long)num * sizeof(struct coordinate), "expanding curve points");
  196.        }
  197.        ip->p_max = num;
  198.     } else {
  199.        if (ip->points != (struct coordinate GPHUGE *) NULL)
  200.         free(ip->points);
  201.        ip->points = (struct coordinate GPHUGE *) NULL;
  202.        ip->p_max = 0;
  203.     }
  204. }
  205.  
  206. /*
  207.  * iso_free() releases any memory which was previously malloc()'d to hold
  208.  *   iso curve points.
  209.  */
  210. void iso_free(ip)
  211. struct iso_curve *ip;
  212. {
  213.     if (ip) {
  214.         if (ip->points)
  215.             free((char *)ip->points);
  216.         free((char *)ip);
  217.     }
  218. }
  219.  
  220. /*
  221.  * sp_alloc() allocates a surface_points structure that can hold 'num_iso_1'
  222.  * iso-curves with 'num_samp_2' samples and 'num_iso_2' iso-curves with
  223.  * 'num_samp_1' samples.
  224.  * If, however num_iso_2 or num_samp_1 is zero no iso curves are allocated.
  225.  */
  226. struct surface_points *
  227. sp_alloc(num_samp_1,num_iso_1,num_samp_2,num_iso_2)
  228.     int num_samp_1,num_iso_1,num_samp_2,num_iso_2;
  229. {
  230.     struct surface_points *sp;
  231.  
  232.     sp = (struct surface_points *) alloc((unsigned long)sizeof(struct surface_points), "surface");
  233.     sp->next_sp = NULL;
  234.     sp->title = NULL;
  235.     sp->contours = NULL;
  236.     sp->iso_crvs = NULL;
  237.     sp->num_iso_read = 0;
  238.  
  239.     if (num_iso_2 > 0 && num_samp_1 > 0) {
  240.     int i;
  241.     struct iso_curve *icrv;
  242.  
  243.     for (i = 0; i < num_iso_1; i++) {
  244.         icrv = iso_alloc(num_samp_2);
  245.         icrv->next = sp->iso_crvs;
  246.         sp->iso_crvs = icrv;
  247.     }
  248.     for (i = 0; i < num_iso_2; i++) {
  249.         icrv = iso_alloc(num_samp_1);
  250.         icrv->next = sp->iso_crvs;
  251.         sp->iso_crvs = icrv;
  252.     }
  253.     } else
  254.     sp->iso_crvs = (struct iso_curve *) NULL;
  255.  
  256.     return(sp);
  257. }
  258.  
  259. /*
  260.  * sp_replace() updates a surface_points structure so it can hold 'num_iso_1'
  261.  * iso-curves with 'num_samp_2' samples and 'num_iso_2' iso-curves with
  262.  * 'num_samp_1' samples.
  263.  * If, however num_iso_2 or num_samp_1 is zero no iso curves are allocated.
  264.  */
  265. void sp_replace(sp,num_samp_1,num_iso_1,num_samp_2,num_iso_2)
  266.        struct surface_points *sp;
  267.        int num_samp_1,num_iso_1,num_samp_2,num_iso_2;
  268. {
  269.     int i;
  270.     struct iso_curve *icrv, *icrvs = sp->iso_crvs;
  271.  
  272.     while ( icrvs ) {
  273.     icrv = icrvs;
  274.     icrvs = icrvs->next;
  275.     iso_free( icrv );
  276.     }
  277.     sp->iso_crvs = NULL;
  278.     
  279.     if (num_iso_2 > 0 && num_samp_1 > 0) {
  280.     for (i = 0; i < num_iso_1; i++) {
  281.         icrv = iso_alloc(num_samp_2);
  282.         icrv->next = sp->iso_crvs;
  283.         sp->iso_crvs = icrv;
  284.     }
  285.     for (i = 0; i < num_iso_2; i++) {
  286.         icrv = iso_alloc(num_samp_1);
  287.         icrv->next = sp->iso_crvs;
  288.         sp->iso_crvs = icrv;
  289.     }
  290.     } else
  291.     sp->iso_crvs = (struct iso_curve *) NULL;
  292. }
  293.  
  294. /*
  295.  * sp_free() releases any memory which was previously malloc()'d to hold
  296.  *   surface points.
  297.  */
  298. void sp_free(sp)
  299. struct surface_points *sp;
  300. {
  301.     if (sp) {
  302.         sp_free(sp->next_sp);
  303.         if (sp->title)
  304.             free((char *)sp->title);
  305.         if (sp->contours) {
  306.             struct gnuplot_contours *cntr, *cntrs = sp->contours;
  307.  
  308.             while (cntrs) {
  309.                 cntr = cntrs;
  310.                 cntrs = cntrs->next;
  311.                 free(cntr->coords);
  312.                 free(cntr);
  313.             }
  314.         }
  315.         if (sp->iso_crvs) {
  316.             struct iso_curve *icrv, *icrvs = sp->iso_crvs;
  317.  
  318.             while (icrvs) {
  319.                 icrv = icrvs;
  320.                 icrvs = icrvs->next;
  321.                 iso_free(icrv);
  322.             }
  323.         }
  324.         free((char *)sp);
  325.     }
  326. }
  327.  
  328.  
  329.  
  330. void save_functions(fp)
  331. FILE *fp;
  332. {
  333. register struct udft_entry *udf = first_udf;
  334.  
  335.     if (fp) {
  336.         while (udf) {
  337.             if (udf->definition)
  338.                 fprintf(fp,"%s\n",udf->definition);
  339.             udf = udf->next_udf;
  340.         }
  341.         (void) fclose(fp);
  342.     } else
  343.         os_error("Cannot open save file",c_token);            
  344. }
  345.  
  346.  
  347. void save_variables(fp)
  348. FILE *fp;
  349. {
  350. register struct udvt_entry *udv = first_udv->next_udv;    /* skip pi */
  351.  
  352.     if (fp) {
  353.         while (udv) {
  354.             if (!udv->udv_undef) {
  355.                 fprintf(fp,"%s = ",udv->udv_name);
  356.                 disp_value(fp,&(udv->udv_value));
  357.                 (void) putc('\n',fp);
  358.             }
  359.             udv = udv->next_udv;
  360.         }
  361.         (void) fclose(fp);
  362.     } else
  363.         os_error("Cannot open save file",c_token);            
  364. }
  365.  
  366.  
  367. void save_all(fp)
  368. FILE *fp;
  369. {
  370. register struct udft_entry *udf = first_udf;
  371. register struct udvt_entry *udv = first_udv->next_udv;    /* skip pi */
  372.  
  373.     if (fp) {
  374.         save_set_all(fp);
  375.         while (udf) {
  376.             if (udf->definition)
  377.                 fprintf(fp,"%s\n",udf->definition);
  378.             udf = udf->next_udf;
  379.         }
  380.         while (udv) {
  381.             if (!udv->udv_undef) {
  382.                 fprintf(fp,"%s = ",udv->udv_name);
  383.                 disp_value(fp,&(udv->udv_value));
  384.                 (void) putc('\n',fp);
  385.             }
  386.             udv = udv->next_udv;
  387.         }
  388.         fprintf(fp,"%s\n",replot_line);
  389.         (void) fclose(fp);
  390.     } else
  391.         os_error("Cannot open save file",c_token);            
  392. }
  393.  
  394.  
  395. void save_set(fp)
  396. FILE *fp;
  397. {
  398.     if (fp) {
  399.         save_set_all(fp);
  400.         (void) fclose(fp);
  401.     } else
  402.         os_error("Cannot open save file",c_token);            
  403. }
  404.  
  405.  
  406. void save_set_all(fp)
  407. FILE *fp;
  408. {
  409. struct text_label *this_label;
  410. struct arrow_def *this_arrow;
  411. char str[MAX_LINE_LEN+1];
  412.     if (term)
  413.         fprintf(fp,"set terminal %s %s\n", term->name, term_options);
  414.     else
  415.         fputs("set terminal unknown\n", fp);
  416.     fprintf(fp,"set output %s\n",strcmp(outstr,"STDOUT")? outstr : "" );
  417.     fprintf(fp,"set %sclip points\n", (clip_points)? "" : "no");
  418.     fprintf(fp,"set %sclip one\n", (clip_lines1)? "" : "no");
  419.     fprintf(fp,"set %sclip two\n", (clip_lines2)? "" : "no");
  420.     fprintf(fp,"set bar %f\n", bar_size);
  421.     fprintf(fp,"set %sborder\n",draw_border ? "" : "no");
  422.     if ( datatype[0] == TIME ) 
  423.         fprintf(fp,"set xdata time\n");
  424.     if ( datatype[1] == TIME ) 
  425.         fprintf(fp,"set ydata time\n");
  426.     if ( datatype[2] == TIME ) 
  427.         fprintf(fp,"set zdata time\n");
  428.     if (boxwidth<0.0)
  429.         fprintf(fp,"set boxwidth\n");
  430.     else
  431.         fprintf(fp,"set boxwidth %g\n",boxwidth);
  432.     if (dgrid3d)
  433.         fprintf(fp,"set dgrid3d %d,%d, %d\n",
  434.             dgrid3d_row_fineness,
  435.             dgrid3d_col_fineness,
  436.             dgrid3d_norm_value);
  437.  
  438.     fprintf(fp,"set dummy %s,%s\n",dummy_var[0], dummy_var[1]);
  439.     fprintf(fp,"set format x \"%s\"\n", conv_text(str,xformat));
  440.     fprintf(fp,"set format y \"%s\"\n", conv_text(str,yformat));
  441.     fprintf(fp,"set format x2 \"%s\"\n", conv_text(str,x2format));
  442.     fprintf(fp,"set format y2 \"%s\"\n", conv_text(str,y2format));
  443.     fprintf(fp,"set format z \"%s\"\n", conv_text(str,zformat));
  444.     if (grid==0)
  445.         fputs("set nogrid\n", fp);
  446.     else {
  447.         if (polar_grid_angle) /* set angle already output */
  448.             fprintf(fp, "set grid polar %f\n", polar_grid_angle/ang2rad);
  449.         else
  450.             fputs("set grid nopolar\n", fp);
  451.         fprintf(fp,"set grid %sxtics %sytics %sztics %sx2tics %sy2tics %smxtics %smytics %smztics %smx2tics %smy2tics %d %d\n",
  452.            grid&GRID_X ? "" : "no",
  453.            grid&GRID_Y ? "" : "no",
  454.            grid&GRID_Z ? "" : "no",
  455.            grid&GRID_X2 ? "" : "no",
  456.            grid&GRID_Y2 ? "" : "no",
  457.            grid&GRID_MX ? "" : "no",
  458.            grid&GRID_MY ? "" : "no",
  459.            grid&GRID_MZ ? "" : "no",
  460.            grid&GRID_MX2 ? "" : "no",
  461.            grid&GRID_MY2 ? "" : "no",
  462.            grid_linetype+1,
  463.            mgrid_linetype+1);
  464.     }
  465.     fprintf(fp,"set key title \"%s\"\n", conv_text(str,key_title));
  466.     switch (key) {
  467.         case -1 : {
  468.             fprintf(fp,"set key");
  469.             switch(key_hpos) {
  470.                 case TRIGHT:
  471.                     fprintf(fp," right");
  472.                     break;
  473.                 case TLEFT:
  474.                     fprintf(fp," left");
  475.                     break;
  476.                 case TOUT:
  477.                     fprintf(fp," out");
  478.                     break;
  479.             }
  480.             switch(key_vpos) {
  481.                 case TTOP:
  482.                     fprintf(fp," top");
  483.                     break;
  484.                 case TBOTTOM:
  485.                     fprintf(fp," bottom");
  486.                     break;
  487.                 case TUNDER:
  488.                     fprintf(fp," below");
  489.                     break;
  490.             }
  491.             break;
  492.             }
  493.         case 0 :
  494.             fprintf(fp,"set nokey\n");
  495.             break;
  496.         case 1 :
  497.             fprintf(fp,"set key ");
  498.             save_position(fp, &key_user_pos);
  499.             break;
  500.     }
  501.     if (key) {
  502.         fprintf(fp, " %s %sreverse box %d\n",
  503.             key_just==JLEFT ? "Left" : "Right", 
  504.            key_reverse ? "" : "no",
  505.            key_box+1);
  506.     }
  507.     fprintf(fp,"set nolabel\n");
  508.     for (this_label = first_label; this_label != NULL;
  509.             this_label = this_label->next) {
  510.         fprintf(fp,"set label %d \"%s\" at ",
  511.                this_label->tag,
  512.                conv_text(str,this_label->text));
  513.         save_position(fp, &this_label->place);
  514.  
  515.         switch(this_label->pos) {
  516.             case LEFT :
  517.                 fprintf(fp," left");
  518.                 break;
  519.             case CENTRE :
  520.                 fprintf(fp," centre");
  521.                 break;
  522.             case RIGHT :
  523.                 fprintf(fp," right");
  524.                 break;
  525.         }
  526.         if ((this_label->font)[0]!='\0')
  527.                         fprintf(fp," font \"%s\"",this_label->font);
  528.                 /* Entry font added by DJL */
  529.         fputc('\n',fp);
  530.     }
  531.     fprintf(fp,"set noarrow\n");
  532.     for (this_arrow = first_arrow; this_arrow != NULL;
  533.             this_arrow = this_arrow->next) {
  534.         fprintf(fp,"set arrow %d from ", this_arrow->tag);
  535.         save_position(fp, &this_arrow->start);
  536.         fputs(" to ", fp);
  537.         save_position(fp, &this_arrow->end);
  538.         fprintf(fp, " %s %d\n",
  539.                this_arrow->head ? "" : " nohead",
  540.                 this_arrow->line);
  541.     }
  542.     fprintf(fp,"set nologscale\n");
  543.     if (is_log_x) fprintf(fp,"set logscale x %g\n", base_log_x);
  544.     if (is_log_y) fprintf(fp,"set logscale y %g\n", base_log_y);
  545.     if (is_log_z) fprintf(fp,"set logscale z %g\n", base_log_z);
  546.     if (is_log_x2) fprintf(fp,"set logscale x2 %g\n", base_log_x2);
  547.     if (is_log_y2) fprintf(fp,"set logscale y2 %g\n", base_log_y2);
  548.     fprintf(fp,"set offsets %g, %g, %g, %g\n",loff,roff,toff,boff);
  549.     fprintf(fp,"set pointsize %g\n", pointsize); 
  550.     fprintf(fp,"set encoding %s\n",encoding_names[encoding]);
  551.     fprintf(fp,"set %spolar\n", (polar)? "" : "no");
  552.     fprintf(fp,"set angles %s\n", (angles_format == ANGLES_RADIANS)?
  553.                         "radians" : "degrees");
  554.     fprintf(fp,"set %sparametric\n", (parametric)? "" : "no");
  555.     fprintf(fp,"set view %g, %g, %g, %g\n",
  556.         surface_rot_x, surface_rot_z, surface_scale, surface_zscale);
  557.     fprintf(fp,"set samples %d, %d\n",samples_1,samples_2);
  558.     fprintf(fp,"set isosamples %d, %d\n",iso_samples_1,iso_samples_2);
  559.     fprintf(fp,"set %ssurface\n",(draw_surface) ? "" : "no");
  560.     fprintf(fp,"set %scontour",(draw_contour) ? "" : "no");
  561.     switch (draw_contour) {
  562.         case CONTOUR_NONE: fprintf(fp, "\n"); break;
  563.         case CONTOUR_BASE: fprintf(fp, " base\n"); break;
  564.         case CONTOUR_SRF:  fprintf(fp, " surface\n"); break;
  565.         case CONTOUR_BOTH: fprintf(fp, " both\n"); break;
  566.     }
  567.     if (label_contours)
  568.          fprintf(fp,"set clabel '%s'\n",contour_format);
  569.      else
  570.          fprintf(fp,"set noclabel\n");
  571.  
  572.     fprintf(fp,"set %shidden3d\n",(hidden3d) ? "" : "no");
  573.     fprintf(fp,"set cntrparam order %d\n", contour_order);
  574.     fprintf(fp,"set cntrparam ");
  575.     switch (contour_kind) {
  576.         case CONTOUR_KIND_LINEAR:    fprintf(fp, "linear\n"); break;
  577.         case CONTOUR_KIND_CUBIC_SPL: fprintf(fp, "cubicspline\n"); break;
  578.         case CONTOUR_KIND_BSPLINE:   fprintf(fp, "bspline\n"); break;
  579.     }
  580.     fprintf(fp,"set cntrparam levels ");
  581.     switch (levels_kind) {
  582.         case LEVELS_AUTO:
  583.             fprintf(fp, "auto %d\n", contour_levels);
  584.             break;
  585.         case LEVELS_INCREMENTAL:
  586.             fprintf(fp, "incremental %g,%g,%g\n",
  587.                 levels_list[0], levels_list[1], 
  588.                 levels_list[0]+levels_list[1]*contour_levels);
  589.             break;
  590.         case LEVELS_DISCRETE:
  591.         {    int i;
  592.             fprintf(fp, "discrete %g", levels_list[0]);
  593.             for(i = 1; i < contour_levels; i++)
  594.                 fprintf(fp, ",%g ", levels_list[i]);
  595.             fprintf(fp, "\n");
  596.         }
  597.     }
  598.     fprintf(fp,"set cntrparam points %d\n", contour_pts);
  599.     fprintf(fp,"set size %ssquare %g,%g\n",square?"":"no",xsize,ysize);
  600.     fprintf(fp,"set origin %g,%g\n",xoffset,yoffset);
  601.     fprintf(fp,"set data style ");
  602.     switch (data_style) {
  603.         case LINES: fprintf(fp,"lines\n"); break;
  604.         case POINTSTYLE: fprintf(fp,"points\n"); break;
  605.         case IMPULSES: fprintf(fp,"impulses\n"); break;
  606.         case LINESPOINTS: fprintf(fp,"linespoints\n"); break;
  607.         case DOTS: fprintf(fp,"dots\n"); break;
  608.         case YERRORBARS: fprintf(fp,"yerrorbars\n"); break;
  609.         case XERRORBARS: fprintf(fp,"xerrorbars\n"); break;
  610.         case XYERRORBARS: fprintf(fp,"xyerrorbars\n"); break;
  611.         case BOXES: fprintf(fp,"boxes\n"); break;
  612.         case BOXERROR: fprintf(fp,"boxerrorbars\n"); break;
  613.         case BOXXYERROR: fprintf(fp,"boxxyerrorbars\n"); break;
  614.         case STEPS: fprintf(fp,"steps\n"); break;       /* JG */
  615.         case FSTEPS: fprintf(fp,"fsteps\n"); break;       /* HOE */
  616.         case VECTOR : fprintf(fp, "vector\n"); break;
  617.     }
  618.     fprintf(fp,"set function style ");
  619.     switch (func_style) {
  620.         case LINES: fprintf(fp,"lines\n"); break;
  621.         case POINTSTYLE: fprintf(fp,"points\n"); break;
  622.         case IMPULSES: fprintf(fp,"impulses\n"); break;
  623.         case LINESPOINTS: fprintf(fp,"linespoints\n"); break;
  624.         case DOTS: fprintf(fp,"dots\n"); break;
  625.         case YERRORBARS: fprintf(fp,"yerrorbars\n"); break;
  626.         case XERRORBARS: fprintf(fp,"xerrorbars\n"); break;
  627.         case XYERRORBARS: fprintf(fp,"xyerrorbars\n"); break;
  628.         case BOXXYERROR: fprintf(fp,"boxxyerrorbars\n"); break;
  629.         case BOXES: fprintf(fp,"boxes\n"); break;
  630.         case BOXERROR: fprintf(fp,"boxerrorbars\n"); break;
  631.         case STEPS: fprintf(fp,"steps\n"); break;       /* JG */
  632.         case FSTEPS: fprintf(fp,"fsteps\n"); break;       /* HOE */
  633.         case VECTOR: fprintf(fp,"vector\n"); break;
  634.     }
  635.         fprintf(fp,"set xzeroaxis %d\n", xzeroaxis+1);
  636.         fprintf(fp,"set x2zeroaxis %d\n", x2zeroaxis+1);
  637.         fprintf(fp,"set yzeroaxis %d\n", yzeroaxis+1);
  638.         fprintf(fp,"set y2zeroaxis %d\n", y2zeroaxis+1);
  639.         fprintf(fp,"set tics %s\n", (tic_in)? "in" : "out");
  640.         fprintf(fp,"set ticslevel %g\n", ticslevel);
  641.     fprintf(fp,"set ticscale %g %g\n", ticscale, miniticscale);
  642.  
  643. #define SAVE_XYZLABEL(name,lab) { \
  644.   fprintf(fp, "set %s \"%s\" %f,%f ", \
  645.     name, conv_text(str,lab.text),lab.xoffset,lab.yoffset); \
  646.   fprintf(fp, " \"%s\"\n", conv_text(str, lab.font)); \
  647. }
  648.  
  649.  
  650. #define SAVE_MINI(name,m,freq) switch(m&TICS_MASK) { \
  651.  case 0: fprintf(fp, "set no %s\n", name); break; \
  652.  case MINI_AUTO: fprintf(fp, "set %s\n",name); break; \
  653.  case MINI_DEFAULT: fprintf(fp, "set %s default\n",name); break; \
  654.  case MINI_USER: fprintf(fp, "set %s %f\n", name, freq); break; \
  655. }
  656.     SAVE_MINI("mxtics", mxtics, mxtfreq)
  657.     SAVE_MINI("mytics", mytics, mytfreq)
  658.     SAVE_MINI("mx2tics", mx2tics, mx2tfreq)
  659.     SAVE_MINI("my2tics", my2tics, my2tfreq)
  660.  
  661.         save_tics(fp, xtics, FIRST_X_AXIS, &xticdef, "x");
  662.         save_tics(fp, ytics, FIRST_Y_AXIS, &yticdef, "y");
  663.         save_tics(fp, ztics, FIRST_Z_AXIS, &zticdef, "z");
  664.         save_tics(fp, x2tics, SECOND_X_AXIS, &x2ticdef, "x2");
  665.         save_tics(fp, y2tics, SECOND_Y_AXIS, &y2ticdef, "y2");
  666.         SAVE_XYZLABEL("title", title);
  667.  
  668.     SAVE_XYZLABEL("timestamp", timelabel);
  669.     save_range(fp,R_AXIS,rmin,rmax,autoscale_r, "r");
  670.     save_range(fp,T_AXIS,tmin,tmax,autoscale_t, "t");
  671.     save_range(fp,U_AXIS,umin,umax,autoscale_u, "u");
  672.     save_range(fp,V_AXIS,vmin,vmax,autoscale_v, "v");
  673.  
  674.     SAVE_XYZLABEL("xlabel", xlabel);
  675.     SAVE_XYZLABEL("x2label", x2label);
  676.  
  677.     if (strlen(timefmt)) {
  678.         fprintf(fp,"set timefmt \"%s\"\n", conv_text(str,timefmt));
  679.     }
  680.     save_range(fp,FIRST_X_AXIS,xmin,xmax,autoscale_x, "x");
  681.      save_range(fp,SECOND_X_AXIS,x2min,x2max,autoscale_x2, "x2");
  682.  
  683.     SAVE_XYZLABEL("ylabel", ylabel);
  684.     SAVE_XYZLABEL("y2label", y2label);
  685.  
  686.     save_range(fp,FIRST_Y_AXIS,ymin,ymax,autoscale_y, "y");
  687.     save_range(fp,SECOND_Y_AXIS,y2min,y2max,autoscale_y2, "y2");
  688.  
  689.     SAVE_XYZLABEL("zlabel", zlabel);
  690.     save_range(fp,FIRST_Z_AXIS,zmin,zmax,autoscale_z, "z");
  691.  
  692.     fprintf(fp,"set zero %g\n",zero);
  693.     fprintf(fp,"set lmargin %d\nset bmargin %d\nset rmargin %d\nset tmargin %d\n",
  694.        lmargin, bmargin, rmargin, tmargin);
  695.  
  696.     fprintf(fp,"set locale \"%s\"\n", cur_locale);
  697. }
  698.  
  699. static void save_tics(fp, where, axis, tdef, text)
  700.     FILE *fp;
  701.     int where;
  702.     int axis;
  703.     struct ticdef *tdef;
  704.     char *text;
  705. {
  706.  
  707.     if (where==NO_TICS) {
  708.     fprintf(fp, "set no%stics\n", text);
  709.     return;
  710.     }
  711.  
  712.        fprintf(fp,"set %stics %s %smirror", text, (where&TICS_MASK)==TICS_ON_AXIS ? "axis" : "border", (where&TICS_MIRROR) ? "" : "no");
  713.        switch(tdef->type) {
  714.           case TIC_COMPUTED: {
  715.              break;
  716.           }
  717.           case TIC_MONTH:{
  718.               fprintf(fp,"\nset %smtics",text);
  719.             break;
  720.           }
  721.             case TIC_DAY:{
  722.             fprintf(fp,"\nset %cdtics",axis);
  723.             break;
  724.             }
  725.           case TIC_SERIES:
  726.              if ( datatype[axis] == TIME ) {
  727.                  if (tdef->def.series.start != -VERYLARGE) {
  728.                    char fd[26];
  729.                     gstrftime(fd,24,timefmt,(double)tdef->def.series.start);
  730.                     fprintf(fp, "\"%s\",", fd);
  731.                 }
  732.                 fprintf(fp,"%g",tdef->def.series.incr);
  733.                 
  734.                 if (tdef->def.series.end != VERYLARGE) {
  735.                     char td[26];
  736.                     gstrftime(td,24,timefmt,(double)tdef->def.series.end);
  737.                     fprintf(fp,",\"%s\"",td);
  738.                 }
  739.                 
  740.             } else {  /* !TIME */
  741.  
  742.                  if (tdef->def.series.start != -VERYLARGE)
  743.                     fprintf(fp, "%g,", tdef->def.series.start);
  744.                 fprintf(fp, "%g", tdef->def.series.incr);
  745.                  if (tdef->def.series.end != VERYLARGE)
  746.                     fprintf(fp, ",%g", tdef->def.series.end);
  747.             }
  748.             
  749.             break;
  750.  
  751.           case TIC_USER: {
  752.              register struct ticmark *t;
  753.              int time;
  754.              time = (datatype[axis] == TIME);
  755.              fprintf(fp, " (");
  756.              for (t = tdef->def.user; t != NULL; t=t->next) {
  757.                 if (t->label)
  758.                     fprintf(fp, "\"%s\" ", t->label);
  759.                 if (time) {
  760.                     char td[26];
  761.                     gstrftime(td,24,timefmt,(double)t->position);
  762.                     fprintf(fp,"\"%s\"",td);
  763.                 } else {
  764.                     fprintf(fp, "%g", t->position);
  765.                 }
  766.                 if (t->next) {
  767.                     fprintf(fp, ", ");
  768.                 }
  769.              }
  770.              fprintf(fp, ")");
  771.              break;
  772.           } 
  773.        }
  774.        putc('\n', fp);
  775. }
  776.  
  777. static void save_position(fp, pos)
  778. FILE *fp;
  779. struct position *pos;
  780. {
  781.     static char *msg[]={"first_axes ","second axes ", "graph ", "screen "};
  782.  
  783.     assert(first_axes==0 && second_axes==1 && graph==2 && screen==3);
  784.     
  785.     fprintf(fp, "%s%g, %s%g, %s%g",
  786.         pos->scalex == first_axes  ? "" : msg[pos->scalex], pos->x,
  787.         pos->scaley == pos->scalex ? "" : msg[pos->scaley], pos->y,
  788.         pos->scalez == pos->scaley ? "" : msg[pos->scalez], pos->z);
  789. }
  790.  
  791. void load_file(fp, name, can_do_args)
  792.     FILE *fp;
  793.     char *name;
  794.     TBOOLEAN can_do_args;
  795. {
  796.     register int len;
  797.  
  798.     int start, left;
  799.     int more;
  800.     int stop = FALSE;
  801.  
  802.     lf_push(fp);        /* save state for errors and recursion */
  803.     do_load_arg_substitution = can_do_args;
  804.  
  805.     if (fp == (FILE *)NULL) {
  806.        char errbuf[BUFSIZ];
  807.        (void) sprintf(errbuf, "Cannot open %s file '%s'",
  808.               can_do_args ? "call" : "load", name);
  809.        os_error(errbuf, c_token);
  810.     } else {
  811.        /* go into non-interactive mode during load */
  812.        /* will be undone below, or in load_file_error */
  813.        interactive = FALSE;
  814.        inline_num = 0;
  815.        infile_name = name;
  816.  
  817.        if (can_do_args) {
  818.               int aix = 0;
  819.                while (++c_token < num_tokens && aix <= 9) {
  820.                       if (isstring(c_token))
  821.                      m_quote_capture(&call_args[aix++], c_token, c_token);
  822.              else
  823.                      m_capture(&call_args[aix++], c_token, c_token);
  824.                }
  825.                if (c_token >= num_tokens && aix > 9)
  826.                      int_error("too many arguments for CALL <file>", ++c_token);
  827.            }
  828.  
  829.        while (!stop) {        /* read all commands in file */
  830.           /* read one command */
  831.           left = input_line_len;
  832.           start = 0;
  833.           more = TRUE;
  834.  
  835.           while (more) {
  836.              if (fgets(&(input_line[start]), left, fp) == (char *)NULL) {
  837.                 stop = TRUE; /* EOF in file */
  838.                 input_line[start] = '\0';
  839.                 more = FALSE;    
  840.              } else {
  841.                 inline_num++;
  842.                 len = strlen(input_line) - 1;
  843.                 if (input_line[len] == '\n') { /* remove any newline */
  844.                     input_line[len] = '\0';
  845.                     /* Look, len was 1-1 = 0 before, take care here! */
  846.                     if (len > 0) --len;
  847.                 } else if (len+2 >= left) {
  848.                     extend_input_line();
  849.                     left=input_line_len-len-1;
  850.                     start=len+1;
  851.                     continue; /* don't check for '\' */
  852.                 }
  853.                 if (input_line[len] == '\\') {
  854.                 /* line continuation */
  855.                     start = len;
  856.                     left  = input_line_len - start;
  857.                 } else
  858.                     more = FALSE;
  859.              }
  860.           }
  861.  
  862.           if (strlen(input_line) > 0) {
  863.                       if (can_do_args) {
  864.              register int il = 0;
  865.                          register char *rl;
  866.              char *raw_line=rl=alloc((unsigned long)strlen(input_line)+1, "string"); 
  867.  
  868.              strcpy(raw_line, input_line);
  869.              *input_line='\0';
  870.              while( *rl ) {
  871.                 register int aix;
  872.                             if (*rl == '$' &&  
  873.                 (aix = *(++rl)) && aix >= '0' && aix <= '9') {
  874.                                if (call_args[aix -= '0']) {
  875.                   len = strlen(call_args[aix]);
  876.                   while(input_line_len-il<len+1) {
  877.                     extend_input_line();
  878.                   }
  879.                                   strcpy(input_line+il, call_args[aix]);
  880.                                   il += len;
  881.                                }
  882.                             } else {
  883.                             /* substitute for $<n> here */
  884.                    if(il+1>input_line_len) {
  885.                  extend_input_line();
  886.                    }
  887.                                input_line[il++] = *rl;
  888.                              }
  889.                  rl++;
  890.                          }
  891.              if(il+1>input_line_len) {
  892.                extend_input_line();
  893.              }
  894.                          input_line[il] = '\0';
  895.              free(raw_line);
  896.               }
  897.               screen_ok = FALSE;    /* make sure command line is
  898.                                echoed on error */
  899.               do_line();
  900.             }
  901.        }
  902.     }
  903.  
  904.     /* pop state */
  905.     (void) lf_pop();        /* also closes file fp */
  906. }
  907.  
  908. /* pop from load_file state stack */
  909. static TBOOLEAN                /* FALSE if stack was empty */
  910. lf_pop()                    /* called by load_file and load_file_error */
  911. {
  912.     LFS *lf;
  913.  
  914.     if (lf_head == NULL)
  915.      return(FALSE);
  916.     else {
  917.            int argindex;
  918.        lf = lf_head;
  919.        if (lf->fp != (FILE *)NULL)
  920.         (void) fclose(lf->fp);
  921.            for (argindex = 0; argindex < 10; argindex++) {
  922.                 if (call_args[argindex]) {
  923.                     free(call_args[argindex]);
  924.                 }
  925.                 call_args[argindex] = lf->call_args[argindex];
  926.            }
  927.            do_load_arg_substitution = lf->do_load_arg_substitution;
  928.        interactive = lf->interactive;
  929.        inline_num = lf->inline_num;
  930.        infile_name = lf->name;
  931.        lf_head = lf->prev;
  932.        free((char *)lf);
  933.        return(TRUE);
  934.     }
  935. }
  936.  
  937. /* push onto load_file state stack */
  938. /* essentially, we save information needed to undo the load_file changes */
  939. static void
  940. lf_push(fp)            /* called by load_file */
  941.     FILE *fp;
  942. {
  943.     LFS *lf;
  944.     int argindex;
  945.     
  946.     lf = (LFS *)alloc((unsigned long)sizeof(LFS), (char *)NULL);
  947.     if (lf == (LFS *)NULL) {
  948.        if (fp != (FILE *)NULL)
  949.         (void) fclose(fp);        /* it won't be otherwise */
  950.        int_error("not enough memory to load file", c_token);
  951.     }
  952.      
  953.     lf->fp = fp;            /* save this file pointer */
  954.     lf->name = infile_name;    /* save current name */
  955.     lf->interactive = interactive;    /* save current state */
  956.     lf->inline_num = inline_num; /* save current line number */
  957.     lf->do_load_arg_substitution = do_load_arg_substitution;
  958.     for (argindex = 0; argindex < 10; argindex++) {
  959.        lf->call_args[argindex] = call_args[argindex];
  960.        call_args[argindex] = NULL;    /* initially no args */
  961.     }
  962.     lf->prev = lf_head;        /* link to stack */
  963.     lf_head = lf;
  964. }
  965.  
  966. FILE *lf_top()        /* used for reread  vsnyder@math.jpl.nasa.gov */
  967. {   if (lf_head == (LFS *) NULL) return((FILE *)NULL);
  968.     return(lf_head->fp);
  969. }
  970.  
  971.  
  972. void load_file_error()            /* called from main */
  973. {
  974.     /* clean up from error in load_file */
  975.     /* pop off everything on stack */
  976.     while(lf_pop())
  977.      ;
  978. }
  979.  
  980. /* find char c in string str; return p such that str[p]==c;
  981.  * if c not in str then p=strlen(str)
  982.  */
  983. #ifdef ANSI_C
  984. int instring(char *str,char c)
  985. #else
  986. int
  987. instring(str, c)
  988.     char *str;
  989.     char c;
  990. #endif
  991. {
  992.     int pos = 0;
  993.  
  994.     while (str != NULL && *str != '\0' && c != *str) {
  995.        str++; 
  996.        pos++;
  997.     }
  998.     return (pos);
  999. }
  1000.  
  1001. void show_functions()
  1002. {
  1003. register struct udft_entry *udf = first_udf;
  1004.  
  1005.     fprintf(stderr,"\n\tUser-Defined Functions:\n");
  1006.  
  1007.     while (udf) {
  1008.         if (udf->definition)
  1009.             fprintf(stderr,"\t%s\n",udf->definition);
  1010.         else
  1011.             fprintf(stderr,"\t%s is undefined\n",udf->udf_name);
  1012.         udf = udf->next_udf;
  1013.     }
  1014. }
  1015.  
  1016.  
  1017. void show_at()
  1018. {
  1019.     (void) putc('\n',stderr);
  1020.     disp_at(temp_at(),0);
  1021. }
  1022.  
  1023.  
  1024. void disp_at(curr_at, level)
  1025. struct at_type *curr_at;
  1026. int level;
  1027. {
  1028. register int i, j;
  1029. register union argument *arg;
  1030.  
  1031.     for (i = 0; i < curr_at->a_count; i++) {
  1032.         (void) putc('\t',stderr);
  1033.         for (j = 0; j < level; j++)
  1034.             (void) putc(' ',stderr);    /* indent */
  1035.  
  1036.             /* print name of instruction */
  1037.  
  1038.         fputs(ft[(int)(curr_at->actions[i].index)].f_name,stderr);
  1039.         arg = &(curr_at->actions[i].arg);
  1040.  
  1041.             /* now print optional argument */
  1042.  
  1043.         switch(curr_at->actions[i].index) {
  1044.           case PUSH:    fprintf(stderr," %s\n", arg->udv_arg->udv_name);
  1045.                     break;
  1046.           case PUSHC:    (void) putc(' ',stderr);
  1047.                     disp_value(stderr,&(arg->v_arg));
  1048.                     (void) putc('\n',stderr);
  1049.                     break;
  1050.           case PUSHD1:    fprintf(stderr," %c dummy\n",
  1051.                       arg->udf_arg->udf_name[0]);
  1052.                     break;
  1053.           case PUSHD2:    fprintf(stderr," %c dummy\n",
  1054.                       arg->udf_arg->udf_name[1]);
  1055.                     break;
  1056.           case CALL:    fprintf(stderr," %s", arg->udf_arg->udf_name);
  1057.                     if(level < 6) {
  1058.                     if (arg->udf_arg->at) {
  1059.                         (void) putc('\n',stderr);
  1060.                         disp_at(arg->udf_arg->at,level+2); /* recurse! */
  1061.                     } else
  1062.                         fputs(" (undefined)\n",stderr);
  1063.                     } else
  1064.                         (void) putc('\n',stderr);
  1065.                     break;
  1066.           case CALLN:    fprintf(stderr," %s", arg->udf_arg->udf_name);
  1067.                     if(level < 6) {
  1068.                     if (arg->udf_arg->at) {
  1069.                         (void) putc('\n',stderr);
  1070.                         disp_at(arg->udf_arg->at,level+2); /* recurse! */
  1071.                     } else
  1072.                         fputs(" (undefined)\n",stderr);
  1073.                     } else
  1074.                         (void) putc('\n',stderr);
  1075.                     break;
  1076.           case JUMP:
  1077.           case JUMPZ:
  1078.           case JUMPNZ:
  1079.           case JTERN:
  1080.                     fprintf(stderr," +%d\n",arg->j_arg);
  1081.                     break;
  1082.           default:
  1083.                     (void) putc('\n',stderr);
  1084.         }
  1085.     }
  1086. }
  1087.  
  1088. /* find max len of keys and count keys with len > 0 */
  1089.  
  1090. int 
  1091. find_maxl_keys(plots,count,kcnt)
  1092. struct curve_points *plots;
  1093. int count, *kcnt;
  1094. {
  1095.     int mlen, len, curve, cnt;
  1096.     register struct curve_points *this_plot;
  1097.  
  1098.     mlen = cnt = 0;
  1099.     this_plot = plots;
  1100.     for (curve = 0; curve < count; this_plot = this_plot->next_cp, curve++)
  1101.         if (this_plot->title && (len = /*assign*/ strlen(this_plot->title))) {
  1102.             cnt++;
  1103.             if (len > mlen) 
  1104.                 mlen = strlen(this_plot->title);
  1105.         }
  1106.     if ( kcnt != NULL ) *kcnt = cnt;
  1107.     return(mlen);
  1108. }
  1109.  
  1110. int 
  1111. find_maxl_keys3d(plots,count,kcnt)
  1112. struct surface_points *plots;
  1113. int count, *kcnt;
  1114. {
  1115.     int mlen, len, surf, cnt;
  1116.     struct surface_points *this_plot;
  1117.  
  1118.     mlen = cnt = 0;
  1119.     this_plot = plots;
  1120.     for (surf = 0; surf < count; this_plot = this_plot->next_sp, surf++) {
  1121.         if (this_plot->title && *this_plot->title &&
  1122.              (draw_surface || (draw_contour && !label_contours))) {
  1123.         ++cnt;
  1124.         len = strlen(this_plot->title);
  1125.         if (len > mlen) 
  1126.             mlen = len;
  1127.          }
  1128.         if (draw_contour && label_contours && this_plot->contours != NULL) {
  1129.             len = find_maxl_cntr(this_plot->contours,&cnt);
  1130.             if ( len > mlen ) 
  1131.                 mlen = len;
  1132.         }
  1133.         }
  1134.     if ( kcnt != NULL ) *kcnt = cnt;
  1135.     return(mlen);
  1136. }
  1137.  
  1138. static int
  1139. find_maxl_cntr(contours,count)
  1140. struct gnuplot_contours *contours;
  1141. int *count;
  1142. {
  1143.     register int cnt;
  1144.     register int mlen, len;
  1145.     register struct gnuplot_contours *cntrs = contours;
  1146.  
  1147.     mlen = cnt = 0;
  1148.     while (cntrs) {
  1149.         if(label_contours && cntrs->isNewLevel) {
  1150.             len = strlen(cntrs->label);
  1151.             if (len)
  1152.                 cnt++;
  1153.             if (len > mlen)
  1154.                 mlen = len;
  1155.         }
  1156.         cntrs = cntrs->next;
  1157.     }
  1158.     *count += cnt;
  1159.     return(mlen);
  1160. }
  1161.  
  1162. static void
  1163. save_range(fp,axis,min,max,autosc,text)
  1164. FILE *fp;
  1165. int axis;
  1166. double min,max;
  1167. TBOOLEAN autosc;
  1168. char *text;
  1169. {
  1170.     char s[25];
  1171.     int i;
  1172.  
  1173.     i = axis;
  1174.     fprintf(fp,"set %srange [ ",text);
  1175.     if ( autosc & 1 ) {
  1176.         fprintf(fp,"*");
  1177.     } else {
  1178.         if ( datatype[axis] == TIME ) {
  1179.             fprintf(fp,"\"");
  1180.             gstrftime(s,24,timefmt,(double)min);
  1181.             for(i=0;i<strlen(s);i++) {
  1182.                 if ( s[i] == '\t' ) 
  1183.                     fprintf(fp,"\\t");
  1184.                 else if ( s[i] > 126 || s[i] < 32 )
  1185.                     fprintf(fp,"\\%o",s[i]);
  1186.                 else
  1187.                     fprintf(fp,"%c",s[i]);
  1188.             }
  1189.             fprintf(fp,"\"");
  1190.         } else
  1191.             fprintf(fp,"%g",min);
  1192.     }
  1193.     fprintf(fp," : ");
  1194.     if ( autosc & 2 ) {
  1195.         fprintf(fp,"*");
  1196.     } else {
  1197.         if ( datatype[axis] == TIME ) {
  1198.             fprintf(fp,"\"");
  1199.             gstrftime(s,24,timefmt,(double)max);
  1200.             for(i=0;i<strlen(s);i++) {
  1201.                 if ( s[i] == '\t' ) 
  1202.                     fprintf(fp,"\\t");
  1203.                 else if ( (s[i] & 0177) < 127 && (s[i] & 0177) > 31 )
  1204.                     fprintf(fp,"%c",s[i]);
  1205.                 else
  1206.                     fprintf(fp,"\\%o",s[i]);
  1207.             }
  1208.             fprintf(fp,"\"");
  1209.         } else 
  1210.             fprintf(fp,"%g",max);
  1211.     }
  1212.     fprintf(fp," ] %sreverse %swriteback\n",
  1213.         range_flags[axis] & RANGE_REVERSE ? "" : "no",
  1214.         range_flags[axis] & RANGE_WRITEBACK ? "" : "no");
  1215. }
  1216.  
  1217.  
  1218. /* check user defined format strings for valid double conversions */
  1219. #ifdef ANSI_C
  1220. TBOOLEAN valid_format( const char *format) 
  1221. #else
  1222. TBOOLEAN valid_format( format) 
  1223. const char *format;
  1224. #endif
  1225. {
  1226.   for (;;) {
  1227.     if (!(format = strchr( format, '%')))  /* look for format spec  */
  1228.       return TRUE;                         /* passed Test           */
  1229.     do {                                   /* scan format statement */
  1230.       format++;                            
  1231.     } while (strchr( "+-#0123456789.", *format));
  1232.     
  1233.     switch (*format) {                     /* Now at format modifier */
  1234.     case '*' :       /* Ignore '*' statements */
  1235.     case '%' :       /* Char   '%' itself     */
  1236.       format++;
  1237.       continue;
  1238.       break;       
  1239.     case 'l' :       /* Now we found it !!! */
  1240.       if (!strchr( "fFeEgG", format[1])) /* looking for a valid format */
  1241.     return FALSE;
  1242.       format++;
  1243.       break;
  1244.     default :
  1245.       return FALSE;
  1246.     }
  1247.   }
  1248. }
  1249.